#include "main.h"

#pragma bss-name (push,"ZEROPAGE")
#pragma data-name (push,"ZEROPAGE")

u8 oam_off;
u16 addr;

u8 gamemode;

u8 bgbuf[128];
u8 scorebuf[7];

u8 zapper, zappershot, zapperdark, zappertmp;

u8 sfxctr;
u16 musicctr, musiclimit;

// game.c ZP vars
u8 x, y, i, ctrl, ctrl2, spintime, aiming, spinchange, progress;
u8 spinprogress, spinframe, prevctrl, prevctrl2, bulletstate[3], five, otherchar;
u8 cocked, died, face1, face2, whichdeath, yelled[2], totalstrikes[2];
u16 strikecnt, strikelimit;
u8 turn, shoottimer;
u8 aiwait, aihesitate;
u8 eggshot, eggfirst;

#pragma data-name(pop)
#pragma bss-name (pop)

#pragma bss-name (push,"SRAM")

u16 topscore[4], checksum;

#pragma bss-name (pop)

void bankswitch(const u8 bank, const u8 file) {
	#define BANKSEL *((u8 *) 0x8000)
	#define BANKFILE *((u8 *) 0x8001)

	// Banks 0 and 1 are 2kb sprite, 2,3,4,5 are 1kb bg

	// Sel: bit 7 1 for 1kb bg granularity, bit 6 0 for working prg
	BANKSEL = 128 | (bank & 0x7);
	BANKFILE = file;

	#undef BANKSEL
	#undef BANKFILE
}

#pragma rodata-name (push, "LOWPRG")

static const u8 intromap[130] = {
	64, 65, 66, 66, 66, 67, 68, 66, 66, 66, 66, 66, 66, 66, 66, 66,
	69, 66, 66, 66, 66, 66, 66, 66, 66, 66, 70, 71, 72, 73, 74, 75,
	76, 77, 78, 79, 80, 72, 73, 74, 81, 82, 83, 66, 66, 66, 84, 85,
	66, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 91,
	92, 93, 100, 101, 83, 102, 103, 104, 105, 106, 107, 108, 101, 109, 89, 90,
	110, 111, 110, 112, 113, 114, 115, 116, 117, 110, 111, 110, 118, 119, 83, 120,
	121, 122, 123, 124, 125, 126, 66, 126, 127, 128, 129, 130, 129, 131, 132, 133,
	134, 135, 136, 129, 130, 129, 137, 138, 139, 66, 66, 140, 141, 142, 143, 144,
	66, 144,
};

#pragma rodata-name (pop)

static u8 checkzapper() {
	static u16 i;
	static u8 tmp;

	ppu_wait_nmi();
	for (i = 0; i < 1000; i++) {
		tmp = *((u8 *) 0x4017);
		if (tmp & 8)
			return 1;
	}

	return 0;
}

#pragma code-name (push, "LOWPRG")

static void credits() {

	vram_adr(NAMETABLE_A);
	vram_fill(0, 1024);

	#define STY 8

	vram_adr(NTADR_A(2, STY));
	str("DESIGN AND SOUND");

	vram_adr(NTADR_A(16, STY + 2));
	str("JAMES CALDERON");

	vram_adr(NTADR_A(2, STY + 5));
	str("PROGRAMMING");

	vram_adr(NTADR_A(17, STY + 7));
	str("LAURI KASANEN");

	vram_adr(NTADR_A(2, STY + 10));
	str("QUALITY AND TESTING");

	vram_adr(NTADR_A(16, STY + 12));
	str("DAMIAN YERRICK");

	#undef STY

	ppu_on_all();

	delay(7);
	zappershot = 0;
	zappertmp = 0;

	while (1) {
		ppu_wait_zapper();

		if (zappershot) {
			break;
		}
	}

	ppu_off();
	delay(30);
}

void shotscreen() {

	// Create a white frame to see if it points at screen
	ppu_wait_nmi();
	while ((*((u8 *) 0x2002)) & 0x80);

	pal_bright(8);
	ppu_wait_nmi();

	// Dummy read
	zapperdark = *((u8 *) 0x2002);

	while (1) {
		zapperdark = *((u8 *) 0x4017);
		zapperdark &= 8;

		if (!zapperdark)
			break;

		if ((*((u8 *) 0x2002)) & 0x80)
			break;
	}

	pal_bright(4);
}

#pragma code-name (pop)

static void intro() {

	static u8 i, x, y;

	pal_col(1, 0x30);

	bankswitch(3, CHR_INTENDON1);
	bankswitch(4, CHR_INTENDON2);

	i = 0;
	for (y = 0; y < 5; y++) {
		for (x = 0; x < 26; x++) {
			vram_adr(NTADR_A(3 + x, 8 + y));
			vram_put(intromap[i++]);
		}
	}

	vram_adr(NTADR_A(6, 16));
	str("A CLASSIC EXPERIENCE");

	zappershot = 0;
	zappertmp = 0;

	ppu_on_all();

	for (i = 0; i < 180; i++) {
		ppu_wait_zapper();

		if (zapper && zappershot) {
			shotscreen();

			delay(7);
			zappershot = 0;
			zappertmp = 0;

			if (!zapperdark) {
				ppu_off();
				credits();
				return;
			}
		}
	}

	ppu_off();
	delay(30);
}

#define CHECKSUM 0xCAFE
void resetscores() {
	topscore[0] = 120;
	topscore[1] = 120;
	topscore[2] = 120;
	topscore[3] = 120;
	checksum = CHECKSUM;
}

int main() {

	#define RAMPROTECT *((u8 *) 0xa001)
	#define IRQDISABLE *((u8 *) 0xe000)

	RAMPROTECT = 0x80; // Enable SRAM and allow writing
	IRQDISABLE = 1;

	// Dummy switches just in case
	bankswitch(5, CHR_EMPTY);
	bankswitch(7, 0);

	zapper = checkzapper();
	zappershot = 0;

	joy_install(joy_static_stddrv);

	bank_spr(1);

	bankswitch(0, 0);
	bankswitch(1, 2);
	bankswitch(2, CHR_FONT);

	if (checksum != CHECKSUM) {
		resetscores();
	}

	set_vram_update(bgbuf);
	bgbuf[0] = NT_UPD_EOF;

//	intro();

	while (1) {
		title();
		game();
	}

	return 0;
}
